package com.ld.security.common.core.util;

import cn.hutool.core.lang.Console;
import com.ld.security.common.core.anno.IdKey;
import com.ld.security.common.core.base.column.ListString;
import com.ld.security.common.core.base.column.SuperColumn;
import com.ld.security.common.core.base.entity.ELangEntity;
import com.ld.security.common.core.base.po.SuperPo;
import com.ld.security.common.core.constant.LangConstant;
import com.ld.security.common.core.exception.ApiException;
import lombok.Data;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;


public class ReflectionUtil {

	private static final String set_prefix = "set";

	private static final String get_prefix = "get";

	private static final String is_prefix = "is";

	public static final String sp_prefix = "\\.";
	/**
	 * 判断对象是否空
	 * @param obj
	 * @return
	 */
	public static boolean isNull(Object val){
		if(val instanceof Collection){
			Collection col = (Collection) val;
			if(!col.isEmpty()){
				return false;
			}
		}else if(val instanceof Map){
			Map map = (Map) val;
			if(map.keySet().size() > 0){
				return false;
			}
		} else if(val instanceof String){
			boolean b= TemplateUtil.isNull(val.toString());
			if(!b){
				return false;
			}
		} else if(val instanceof SuperPo){
			for (Field field : getAllDeclaredFields(val.getClass())) {
				Object v = invokeGetter(val,field.getName());
				if(!isNull(v)){
					return  false;
				}
			}
		}else{
			return val == null;
		}
		return true;
	}

	/**
	 * 填充实体属性
	 * @param obj
	 */
	public static void fill(Object obj){
		if(obj instanceof ELangEntity){
			ELangEntity eLangEntity = (ELangEntity)obj;
			if(TemplateUtil.isNull(eLangEntity.getLangKey())){
				eLangEntity.setLangKey(UuidUtil.getId());
			}
			if(TemplateUtil.isNull(eLangEntity.getCrtLang())){
				eLangEntity.setCrtLang(LangConstant.zh_simp.getValue());
			}
		}
		for (Field field : getAllDeclaredFields(obj.getClass())) {

			Object value = ReflectionUtil.invokeGetter(obj,field.getName());
			if(value != null) {
				continue;
			}
			Class clazz = field.getType();
			if(Integer.class.isAssignableFrom(clazz)) {
				value=0;
			}else if(Double.class.isAssignableFrom(clazz)) {
				value=0.0;
			}else if(Boolean.class.isAssignableFrom(clazz)) {
				value= false;
			}else if(Date.class.isAssignableFrom(clazz)) {
				value= new Date();
			}else if(String.class.isAssignableFrom(clazz)) {
				value="";
			}else if(SuperColumn.class.isAssignableFrom(clazz)){
				value = newInstance(clazz);
				if(value instanceof ListString){
					ListString listString = (ListString)value;
					listString.add("0");
				}
			}else if(clazz.isEnum()){
				Object[] as =  clazz.getEnumConstants();
				if(as.length > 0){
					value =as[0];
				}
			}else if(List.class.isAssignableFrom(clazz)){
				value = new LinkedList<>();
			}else if(Map.class.isAssignableFrom(clazz)){
				value = new HashMap<>();
			}
			if(value != null){
				ReflectionUtil.invokeSetter(obj,field.getName(), value);
			}


		}
	}

	/**
	 * 实体类型转型
	 * @param val
	 * @param cla
	 * @param <E>
	 * @return
	 */
	public static <E> E clone(Object val,Class<E> cla){
		return JsonUtil.toObject( JsonUtil.toJson(val),cla);
	}




	/**
	 *  对字段预处理
	 * @param obj
	 * @param aClazz
	 * @param f
	 * @param <E>
	 */
	public static <E extends Annotation> void applyAllDeclaredFields(Object obj,Class<E> aClazz, FieldFunc<E> f) {

		for (Field field : getAllDeclaredFields(obj.getClass())) {
			E anno = AnnotationUtils.findAnnotation(field,aClazz);
			if(anno == null){
				Method method =  getGetMethod(obj.getClass(),field.getName());
				anno =  AnnotationUtils.findAnnotation(method,aClazz);
			}
			if(anno == null){
				continue;
			}
			Object val =  invokeGetter(obj,field.getName());

			f.run(anno,field.getName(),val);
		}

	}

		/**
         * 得到所有字段
         * @param clazz
         * @return
         */
	public static List<Field> getAllDeclaredFields(Class<?> clazz) {
		List<Field> list = new LinkedList<>();
		while(clazz != null) {
			for(Field field:clazz.getDeclaredFields()) {
				if(Modifier.isStatic(field.getModifiers())){
					continue;
				}
				list.add(field);
			}
			clazz = clazz.getSuperclass();
		}
		return list;
	}


	private static Method getGetMethod(Class clazz,String name){
		String methodName =get_prefix + TemplateUtil.toUpperCaseFirstOne(name);
		Method method = ReflectionUtils.findMethod(clazz,methodName);
		if(method == null){
			methodName =is_prefix + TemplateUtil.toUpperCaseFirstOne(name);
			method = ReflectionUtils.findMethod(clazz,methodName);
		}
		return method;
	}




	public static <E> E newInstance(Class<E> cla){
		try{
			return cla.newInstance();
		}catch (Exception e){
			throw new RuntimeException("实例化异常:"+cla);
		}

	}

	/**
	 * 调用Getter方法.
	 * 支持多级，如：对象名.对象名.方法
	 */
	public static <E> E invokeGetter(Object obj, String propertyName) {
		Object object = obj;
		String[] names = propertyName.split(sp_prefix);

		for (String name : names){
			if(object == null){
				ApiException.throw400("异常获取值:"+names);
			}
			if(object instanceof  Map){
				Map map = (Map)object;
				object = map.get(name);
			}else{
				Method method = getGetMethod(object.getClass(),name);
				if(method == null){
					ApiException.throw400(object.getClass()+"异常属性"+propertyName);
				}
				method.setAccessible(true);
				object = ReflectionUtils.invokeMethod(method,object);
			}

		}
		return (E)object;
	}

	/**
	 * 调用Setter方法, 仅匹配方法名。
	 * 支持多级，如：对象名.对象名.方法
	 */
	public static void invokeSetter(Object obj, String propertyName, Object value) {
		Object object = obj;
		String[] names = propertyName.split(sp_prefix);

		for (String name : names){
			String methodName =set_prefix + TemplateUtil.toUpperCaseFirstOne(name);
			Method method=null ;
			if(value != null){
				//根据名称获取
				Class<?> valClazz = obj.getClass();
				for (Method method1 : valClazz.getMethods()) {
					if(method1.getName().equals(methodName)){
						method =method1;
						break;
					}
				}
			}else{
				method = ReflectionUtils.findMethod(object.getClass(),methodName);
			}

			if(method == null){
				ApiException.throw400(object.getClass()+"异常属性"+propertyName);
			}
			method.setAccessible(true);
			object = ReflectionUtils.invokeMethod(method,object,value);
		}

	}


	@Setter
	public static class User{

		private String id;
		private String userName;
		@IdKey("userName")
		public String getId() {
			return id;
		}

		public String getUserName() {
			return userName;
		}

	}

	public static void main(String[] args){
		User u =  new User();
		ReflectionUtil.invokeSetter(u,"userName","1");
		UuidUtil.initIdKey(u);
		Console.log(u.getId());
	}


}